import React from 'react';
import { Card, Form, Input, Button, Space, Tag, Drawer, Spin, message, Pagination } from 'antd';

// 设备地图页面（切换为腾讯地图，支持 GL 优先、JS 2D 回退）
export default function MachineMaps() {
  const [form] = Form.useForm();
  const mapRef = React.useRef(null);
  const markersRef = React.useRef([]); // 用于 2D API 的 Marker 列表
  const markerLayerRef = React.useRef(null); // 用于 GL API 的 MultiMarker 图层
  const markersIndexRef = React.useRef({}); // 通过设备编号映射到标记或坐标
  const infoWindowRef = React.useRef(null);
  const isGLRef = React.useRef(false); // 是否为 TMap GL
  const leafletLayerRef = React.useRef(null); // Leaflet 图层组（OSM 回退）
  const mapKindRef = React.useRef(''); // 'tencent-gl' | 'tencent-2d' | 'leaflet'

  // 地图加载状态
  const [loading, setLoading] = React.useState(true);
  const [rightLoading, setRightLoading] = React.useState(true);
  const [mapError, setMapError] = React.useState('');
  const [keyInfo, setKeyInfo] = React.useState(''); // 调试：显示当前读取到的 KEY（部分掩码）
  const [drawerItem, setDrawerItem] = React.useState(null);
  const [mapMode, setMapMode] = React.useState(''); // 当前地图引擎模式展示

  // 搜索条件
  const [search, setSearch] = React.useState({ equipmentNo: '', equipmentName: '' });

  // 示例设备位置数据（包含经纬度）
  const [positions, setPositions] = React.useState(() => ([
    // 已有示例
    { equipmentNo: 'A1-001', equipmentName: '自动售货机 A1-001', nickName: '张三', locale: '上海市徐汇区', mqState: 1, totalNum: 120, totalSales: 5200, mqLen: '6h20m', lat: 31.194, lng: 121.436, remoteCode: '', remoteId: '' },
    { equipmentNo: 'B3-210', equipmentName: '自动售货机 B3-210', nickName: '李四', locale: '上海市浦东新区', mqState: 0, totalNum: 0, totalSales: 0, mqLen: '0h', lat: 31.230, lng: 121.476, remoteCode: '', remoteId: '' },
    { equipmentNo: 'C2-045', equipmentName: '自动售货机 C2-045', nickName: '王五', locale: '广州市天河区', mqState: 1, totalNum: 85, totalSales: 4300, mqLen: '8h12m', lat: 23.132, lng: 113.322, remoteCode: '', remoteId: '' },
    { equipmentNo: 'D9-077', equipmentName: '自动售货机 D9-077', nickName: '赵六', locale: '北京市海淀区', mqState: 1, totalNum: 66, totalSales: 3200, mqLen: '12h05m', lat: 39.959, lng: 116.298, remoteCode: '', remoteId: '' },
    // 新增六台设备（分布在一二线城市）
    { equipmentNo: 'E5-118', equipmentName: '自动售货机 E5-118', nickName: '孙七', locale: '深圳市南山区', mqState: 1, totalNum: 102, totalSales: 4800, mqLen: '5h45m', lat: 22.543, lng: 114.057, remoteCode: '', remoteId: '' },
    { equipmentNo: 'F1-302', equipmentName: '自动售货机 F1-302', nickName: '周八', locale: '杭州市西湖区', mqState: 1, totalNum: 95, totalSales: 4100, mqLen: '7h10m', lat: 30.274, lng: 120.155, remoteCode: '', remoteId: '' },
    { equipmentNo: 'G9-210', equipmentName: '自动售货机 G9-210', nickName: '吴九', locale: '成都市锦江区', mqState: 0, totalNum: 0, totalSales: 0, mqLen: '0h', lat: 30.67, lng: 104.06, remoteCode: '', remoteId: '' },
    { equipmentNo: 'H2-088', equipmentName: '自动售货机 H2-088', nickName: '郑十', locale: '南京市鼓楼区', mqState: 1, totalNum: 76, totalSales: 3600, mqLen: '9h20m', lat: 32.061, lng: 118.792, remoteCode: '', remoteId: '' },
    { equipmentNo: 'J4-135', equipmentName: '自动售货机 J4-135', nickName: '钱十一', locale: '武汉市江汉区', mqState: 1, totalNum: 88, totalSales: 3900, mqLen: '6h05m', lat: 30.592, lng: 114.305, remoteCode: '', remoteId: '' },
    { equipmentNo: 'K3-420', equipmentName: '自动售货机 K3-420', nickName: '赵十二', locale: '西安市雁塔区', mqState: 0, totalNum: 0, totalSales: 0, mqLen: '0h', lat: 34.341, lng: 108.939, remoteCode: '', remoteId: '' },
  ]));

  const [showPositions, setShowPositions] = React.useState([]);
  // 分页：每页 5 个
  const [page, setPage] = React.useState(1);
  const PAGE_SIZE = 5;
  const paginatedPositions = React.useMemo(() => {
    const start = (page - 1) * PAGE_SIZE;
    return showPositions.slice(start, start + PAGE_SIZE);
  }, [showPositions, page]);
  // 防止在 React 严格模式或重复触发 useEffect 时多次初始化地图
  const initOnceRef = React.useRef(false);

  // 坐标归一化与校验工具
  const toNumber = (v) => {
    if (typeof v === 'number') return v;
    if (typeof v === 'string') {
      const n = parseFloat(v);
      return Number.isFinite(n) ? n : NaN;
    }
    return NaN;
  };
  const isValidLatLng = (lat, lng) => (
    Number.isFinite(lat) && Number.isFinite(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180
  );
  const normalizeItem = (p) => ({ ...p, lat: toNumber(p.lat), lng: toNumber(p.lng) });

  // 初始化右侧列表
  React.useEffect(() => {
    setRightLoading(true);
    setShowPositions(positions);
    const timer = setTimeout(() => setRightLoading(false), 300);
    return () => clearTimeout(timer);
  }, []);
  // 列表变化时校正当前页避免越界
  React.useEffect(() => {
    const totalPages = Math.max(1, Math.ceil(showPositions.length / PAGE_SIZE));
    if (page > totalPages) setPage(totalPages);
  }, [showPositions, page]);

  // 动态加载腾讯地图脚本并初始化
  React.useEffect(() => {
    if (initOnceRef.current) return; // 只初始化一次地图
    initOnceRef.current = true;
    const keyRaw = import.meta.env.VITE_TENCENT_MAP_KEY;
    const key = String(keyRaw ?? '').trim().replace(/^['"]+|['"]+$/g, ''); // 去除可能的引号
    setKeyInfo(key ? `${key.slice(0, 6)}...` : '空');
    // 若 KEY 缺失，仍尝试使用开源地图（Leaflet + OpenStreetMap）作为回退，保证页面可用

    const loadTMapGLScript = (src) => new Promise((resolve, reject) => {
      if (window.TMap) return resolve();
      const existed = document.getElementById('tencent-map-gl-script');
      if (existed) { try { existed.remove(); } catch (e) {} }
      const script = document.createElement('script');
      script.id = 'tencent-map-gl-script';
      script.src = src;
      script.async = true;
      script.onload = () => {
        if (window.TMap) resolve(); else reject(new Error('TMap GL 未初始化'));
      };
      script.onerror = (e) => reject(e);
      document.head.appendChild(script);
    });

    const loadQQMap2DScript = (src) => new Promise((resolve, reject) => {
      if (window.qq && window.qq.maps) return resolve();
      const existed = document.getElementById('tencent-map-2d-script');
      if (existed) { try { existed.remove(); } catch (e) {} }
      const script = document.createElement('script');
      script.id = 'tencent-map-2d-script';
      script.src = src;
      script.async = true;
      script.onload = () => {
        if (window.qq && window.qq.maps) resolve(); else reject(new Error('QQ Map 2D 未初始化'));
      };
      script.onerror = (e) => reject(e);
      document.head.appendChild(script);
    });

    // Leaflet（开源地图）加载
    const loadLeafletCSS = () => new Promise((resolve) => {
      if (document.getElementById('leaflet-css')) return resolve();
      const link = document.createElement('link');
      link.id = 'leaflet-css';
      link.rel = 'stylesheet';
      link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
      link.onload = () => resolve();
      link.onerror = () => resolve(); // CSS 加载失败也不阻塞
      document.head.appendChild(link);
    });

    const loadLeafletScript = () => new Promise((resolve, reject) => {
      if (window.L) return resolve();
      const existed = document.getElementById('leaflet-js');
      if (existed) { try { existed.remove(); } catch (e) {} }
      const script = document.createElement('script');
      script.id = 'leaflet-js';
      script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
      script.async = true;
      script.onload = () => { if (window.L) resolve(); else reject(new Error('Leaflet 未初始化')); };
      script.onerror = (e) => reject(e);
      document.head.appendChild(script);
    });

    const initGLMap = () => {
      try {
        const container = document.getElementById('mapBox');
        const map = new window.TMap.Map(container, {
          center: new window.TMap.LatLng(31.230, 121.476), // lat, lng（默认上海）
          zoom: 12, // 默认放大显示
        });
        mapRef.current = map;
        isGLRef.current = true;
        mapKindRef.current = 'tencent-gl';
        setMapMode('Tencent GL');

        // 初始化 InfoWindow
        infoWindowRef.current = new window.TMap.InfoWindow({
          map,
          position: new window.TMap.LatLng(31.230, 121.476),
          content: '',
          offset: { x: 0, y: -32 },
        });

        // 创建 MultiMarker 图层
        const styles = {
          marker: new window.TMap.MarkerStyle({
            width: 25,
            height: 35,
            anchor: { x: 12, y: 32 },
            // 不设置自定义图标，使用内置默认样式，避免外链 404
          }),
        };
        // 归一化 & 严格坐标校验
        const normalizedPositions = positions.map(normalizeItem);
        const safePositions = normalizedPositions.filter((p) => isValidLatLng(p.lat, p.lng));
        const geometries = safePositions.map((p) => ({
          position: new window.TMap.LatLng(p.lat, p.lng),
          id: p.equipmentNo,
          styleId: 'marker',
          properties: { p },
        }));

        const layer = new window.TMap.MultiMarker({ map, styles, geometries });
        layer.on('click', (evt) => {
          const g = evt.geometry;
          const item = g.properties?.p;
          if (!item) return;
          const content = `<div style="font-size:12px"><b>${item.equipmentName}</b><br/>设备号：${item.equipmentNo}<br/>位置：${item.locale}<br/>坐标：${item.lat}, ${item.lng}</div>`;
          infoWindowRef.current.setPosition(g.position);
          infoWindowRef.current.setContent(content);
          infoWindowRef.current.open();
        });
        markerLayerRef.current = layer;

        // 建立索引：设备编号 -> 坐标
        markersIndexRef.current = {};
        safePositions.forEach((p) => {
          markersIndexRef.current[p.equipmentNo] = {
            position: new window.TMap.LatLng(p.lat, p.lng),
            data: p,
          };
        });

        setMapError('');
        setLoading(false);
      } catch (e) {
        setMapError('腾讯地图 GL 初始化失败，请检查浏览器兼容性或网络。');
        setLoading(false);
      }
    };

    const init2DMap = () => {
      try {
        const container = document.getElementById('mapBox');
        const map = new window.qq.maps.Map(container, {
          center: new window.qq.maps.LatLng(31.230, 121.476), // lat, lng（默认上海）
          zoom: 12, // 默认放大显示
        });
        mapRef.current = map;
        isGLRef.current = false;
        mapKindRef.current = 'tencent-2d';
        setMapMode('Tencent 2D');

        infoWindowRef.current = new window.qq.maps.InfoWindow({ map });

        // 创建标记（归一化并过滤无效坐标）
        markersRef.current = [];
        markersIndexRef.current = {};
        const normalizedPositions = positions.map(normalizeItem);
        const safePositions = normalizedPositions.filter((p) => isValidLatLng(p.lat, p.lng));
        safePositions.forEach((p) => {
          const pos = new window.qq.maps.LatLng(p.lat, p.lng);
          const marker = new window.qq.maps.Marker({ position: pos, map });
          window.qq.maps.event.addListener(marker, 'click', () => {
            const content = `<div style="font-size:12px"><b>${p.equipmentName}</b><br/>设备号：${p.equipmentNo}<br/>位置：${p.locale}<br/>坐标：${p.lat}, ${p.lng}</div>`;
            infoWindowRef.current.setContent(content);
            infoWindowRef.current.setPosition(pos);
            infoWindowRef.current.open();
          });
          markersRef.current.push(marker);
          markersIndexRef.current[p.equipmentNo] = marker;
        });

        setMapError('');
        setLoading(false);
      } catch (e) {
        setMapError('腾讯地图 2D 初始化失败，请检查网络或 KEY 配置。');
        setLoading(false);
      }
    };

    const initLeafletMap = () => {
      try {
        const container = document.getElementById('mapBox');
        if (!container) throw new Error('地图容器不存在');
        const L = window.L;
        const map = L.map(container).setView([31.230, 121.476], 12); // 默认放大显示
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
          attribution: '&copy; OpenStreetMap contributors',
        }).addTo(map);

        mapRef.current = map;
        isGLRef.current = false;
        mapKindRef.current = 'leaflet';
        setMapMode('OpenStreetMap');

        // 标记图层组
        leafletLayerRef.current = L.layerGroup().addTo(map);
        markersRef.current = [];
        markersIndexRef.current = {};
        // 归一化并过滤无效坐标
        const normalizedPositions = positions.map(normalizeItem);
        const safePositions = normalizedPositions.filter((p) => isValidLatLng(p.lat, p.lng));
        safePositions.forEach((p) => {
          const content = `<div style="font-size:12px"><b>${p.equipmentName}</b><br/>设备号：${p.equipmentNo}<br/>位置：${p.locale}<br/>坐标：${p.lat}, ${p.lng}</div>`;
          const marker = L.marker([p.lat, p.lng]).addTo(leafletLayerRef.current).bindPopup(content);
          markersRef.current.push(marker);
          markersIndexRef.current[p.equipmentNo] = marker;
        });

        setMapError('');
        setLoading(false);
      } catch (e) {
        console.error('Leaflet 初始化失败', e);
        setMapError('开源地图（Leaflet/OSM）初始化失败，请检查网络。');
        setLoading(false);
      }
    };

    const glUrl = `https://map.qq.com/api/gljs?v=1.exp&key=${key}`;
    const twoDUrl = `https://map.qq.com/api/js?v=2.exp&key=${key}`;

    // 等待容器尺寸准备好（避免容器高度为 0 导致地图不渲染）
    const waitContainerReady = () => new Promise((resolve) => {
      const container = document.getElementById('mapBox');
      if (!container) return resolve();
      if (container.clientWidth > 0 && container.clientHeight > 0) return resolve();
      const ro = new ResizeObserver((entries) => {
        const el = entries[0]?.target || container;
        if (el.clientWidth > 0 && el.clientHeight > 0) {
          try { ro.disconnect(); } catch (e) {}
          resolve();
        }
      });
      try { ro.observe(container); } catch (e) { resolve(); }
      // 保险：最多等待 2.5s
      setTimeout(() => resolve(), 2500);
    });

    // 根据设备像素比限制容器的最大尺寸，避免 WebGL 超过最大纹理尺寸导致不渲染
    // 更稳健地获取 GL 能力：综合 MAX_TEXTURE_SIZE、MAX_RENDERBUFFER_SIZE、MAX_VIEWPORT_DIMS
    const getMaxGLDimension = () => {
      let fallback = 4096;
      try {
        const canvas = document.createElement('canvas');
        const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
        if (gl) {
          const tex = gl.getParameter(gl.MAX_TEXTURE_SIZE);
          const rb = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
          const vp = gl.getParameter(gl.MAX_VIEWPORT_DIMS);
          const vpW = Array.isArray(vp) ? (Number(vp[0]) || fallback) : fallback;
          const vpH = Array.isArray(vp) ? (Number(vp[1]) || fallback) : fallback;
          const safeTex = (typeof tex === 'number' && tex > 0) ? tex : fallback;
          const safeRb = (typeof rb === 'number' && rb > 0) ? rb : fallback;
          const base = Math.max(1024, Math.min(safeTex, safeRb, vpW, vpH));
          return base;
        }
      } catch (e) {}
      return fallback; // 保守默认值
    };

    const capMapContainerSize = () => {
      const container = document.getElementById('mapBox');
      if (!container) return;
      const dpr = window.devicePixelRatio || 1;
      const maxGL = getMaxGLDimension();
      const maxCssW = Math.max(320, Math.floor(maxGL / dpr) - 32);
      const maxCssH = Math.max(320, Math.floor(maxGL / dpr) - 32);
      // 设置上限，避免超大容器导致 GL 初始化失败
      container.style.maxWidth = `${maxCssW}px`;
      container.style.maxHeight = `${maxCssH}px`;
      // 若当前尺寸超过上限，直接收缩到上限，保证初始化安全
      const cw = container.clientWidth;
      const ch = container.clientHeight;
      if (cw > maxCssW) container.style.width = `${maxCssW}px`;
      if (ch > maxCssH || ch === 0) container.style.height = `${Math.max(360, maxCssH)}px`;
      // 基线最小高度，防止高度为 0
      if (!container.style.minHeight) container.style.minHeight = '360px';
      // 居中显示，避免缩小后左侧空白不美观
      if (!container.style.margin) container.style.margin = '0 auto';
    };

    const tryLeafletFallback = async (reason) => {
      console.warn('使用开源地图回退:', reason);
      try {
        await waitContainerReady();
        await loadLeafletCSS();
        await loadLeafletScript();
        initLeafletMap();
      } catch (errLeaf) {
        console.error('Leaflet 加载失败', errLeaf);
        setMapError('地图加载失败：腾讯地图与开源地图均未能加载。');
        setLoading(false);
      }
    };

    const tryGLThen2DThenLeaflet = async () => {
      if (!key) {
        // 无 KEY 时直接使用开源地图回退，保证页面可用
        setMapError('未配置腾讯地图 KEY，已切换到开源地图回退（Leaflet/OSM）');
        await tryLeafletFallback('未配置 KEY');
        return;
      }
      try {
        await loadTMapGLScript(glUrl);
        await waitContainerReady();
        capMapContainerSize();
        initGLMap();
        return;
      } catch (errGL) {
        console.warn('TMap GL 加载或初始化失败，尝试降级到 2D', errGL);
        try {
          await loadQQMap2DScript(twoDUrl);
          await waitContainerReady();
          capMapContainerSize();
          init2DMap();
          return;
        } catch (err2D) {
          console.error('腾讯地图加载失败（GL 和 2D 均失败），尝试开源地图回退', errGL, err2D);
          await tryLeafletFallback('腾讯地图 GL 与 2D 均失败');
        }
      }
    };

    tryGLThen2DThenLeaflet();
  }, []);

  // 监听窗口尺寸变化，动态限制地图容器尺寸，避免在用户缩放/最大化窗口后再次触发 GL 纹理尺寸错误
  React.useEffect(() => {
    const onResize = () => {
      try {
        const container = document.getElementById('mapBox');
        if (!container) return;
        // 清除可能的内联宽高以重新计算
        container.style.width = '';
        container.style.height = '';
        // 重新限制尺寸
        const dpr = window.devicePixelRatio || 1;
        const maxGL = (function(){
          let fallback = 4096;
          try {
            const canvas = document.createElement('canvas');
            const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
            if (gl) {
              const tex = gl.getParameter(gl.MAX_TEXTURE_SIZE);
              const rb = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
              const vp = gl.getParameter(gl.MAX_VIEWPORT_DIMS);
              const vpW = Array.isArray(vp) ? (Number(vp[0]) || fallback) : fallback;
              const vpH = Array.isArray(vp) ? (Number(vp[1]) || fallback) : fallback;
              const safeTex = (typeof tex === 'number' && tex > 0) ? tex : fallback;
              const safeRb = (typeof rb === 'number' && rb > 0) ? rb : fallback;
              return Math.max(1024, Math.min(safeTex, safeRb, vpW, vpH));
            }
          } catch (e) {}
          return fallback;
        })();
        const maxCssW = Math.max(320, Math.floor(maxGL / dpr) - 32);
        const maxCssH = Math.max(320, Math.floor(maxGL / dpr) - 32);
        container.style.maxWidth = `${maxCssW}px`;
        container.style.maxHeight = `${maxCssH}px`;
        const cw = container.clientWidth;
        const ch = container.clientHeight;
        if (cw > maxCssW) container.style.width = `${maxCssW}px`;
        if (ch > maxCssH || ch === 0) container.style.height = `${Math.max(360, maxCssH)}px`;
      } catch (e) {}
    };
    window.addEventListener('resize', onResize);
    // 首次调度一次，确保进入页面时尺寸即已被限制
    setTimeout(onResize, 0);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  // 搜索与重置
  const renderGLMarkers = (list) => {
    if (!mapRef.current || !window.TMap) return;
    // 移除旧图层
    try { markerLayerRef.current?.setMap(null); } catch (e) {}
    const styles = {
      marker: new window.TMap.MarkerStyle({
        width: 25,
        height: 35,
        anchor: { x: 12, y: 32 },
        // 使用默认样式，避免外链 404
      }),
    };
    const normalizedList = list.map(normalizeItem);
    const safeList = normalizedList.filter((p) => isValidLatLng(p.lat, p.lng));
    const geometries = safeList.map((p) => ({
      position: new window.TMap.LatLng(p.lat, p.lng),
      id: p.equipmentNo,
      styleId: 'marker',
      properties: { p },
    }));
    const layer = new window.TMap.MultiMarker({ map: mapRef.current, styles, geometries });
    layer.on('click', (evt) => {
      const item = evt.geometry?.properties?.p;
      if (!item) return;
      const content = `<div style="font-size:12px"><b>${item.equipmentName}</b><br/>设备号：${item.equipmentNo}<br/>位置：${item.locale}<br/>坐标：${item.lat}, ${item.lng}</div>`;
      infoWindowRef.current.setPosition(evt.geometry.position);
      infoWindowRef.current.setContent(content);
      infoWindowRef.current.open();
    });
    markerLayerRef.current = layer;
    markersIndexRef.current = {};
    safeList.forEach((p) => {
      markersIndexRef.current[p.equipmentNo] = {
        position: new window.TMap.LatLng(p.lat, p.lng),
        data: p,
      };
    });
    if (safeList.length > 0) {
      const first = safeList[0];
      const pos = new window.TMap.LatLng(first.lat, first.lng);
      const curZoom = typeof mapRef.current.getZoom === 'function' ? mapRef.current.getZoom() : 10;
      mapRef.current.setCenter(pos);
      mapRef.current.setZoom(Math.max(curZoom, 10));
    }
  };

  const render2DMarkers = (list) => {
    if (!mapRef.current || !window.qq || !window.qq.maps) return;
    // 移除旧标记
    markersRef.current.forEach((mk) => { try { mk.setMap(null); } catch (e) {} });
    markersRef.current = [];
    markersIndexRef.current = {};
    const normalizedList = list.map(normalizeItem);
    const safeList = normalizedList.filter((p) => isValidLatLng(p.lat, p.lng));
    safeList.forEach((p) => {
      const pos = new window.qq.maps.LatLng(p.lat, p.lng);
      const marker = new window.qq.maps.Marker({ position: pos, map: mapRef.current });
      window.qq.maps.event.addListener(marker, 'click', () => {
        const content = `<div style="font-size:12px"><b>${p.equipmentName}</b><br/>设备号：${p.equipmentNo}<br/>位置：${p.locale}<br/>坐标：${p.lat}, ${p.lng}</div>`;
        infoWindowRef.current.setContent(content);
        infoWindowRef.current.setPosition(pos);
        infoWindowRef.current.open();
      });
      markersRef.current.push(marker);
      markersIndexRef.current[p.equipmentNo] = marker;
    });
    if (safeList.length > 0) {
      const first = safeList[0];
      const pos = new window.qq.maps.LatLng(first.lat, first.lng);
      const curZoom = typeof mapRef.current.getZoom === 'function' ? mapRef.current.getZoom() : 10;
      mapRef.current.setCenter(pos);
      mapRef.current.setZoom(Math.max(curZoom, 10));
    }
  };

  const handleSearch = async () => {
    const values = await form.validateFields();
    const { equipmentNo = '', equipmentName = '' } = values;
    setSearch({ equipmentNo, equipmentName });
    const filtered = positions.filter((p) => {
      if (equipmentNo && !p.equipmentNo.includes(equipmentNo)) return false;
      if (equipmentName && !p.equipmentName.includes(equipmentName)) return false;
      return true;
    });
    setShowPositions(filtered);
    setPage(1);
    if (!mapRef.current) return;
    if (mapKindRef.current === 'tencent-gl') renderGLMarkers(filtered);
    else if (mapKindRef.current === 'tencent-2d') render2DMarkers(filtered);
    else if (mapKindRef.current === 'leaflet') renderLeafletMarkers(filtered);
  };

  const handleReset = () => {
    form.resetFields();
    setSearch({ equipmentNo: '', equipmentName: '' });
    setShowPositions(positions);
    setPage(1);
    if (!mapRef.current) return;
    if (mapKindRef.current === 'tencent-gl') renderGLMarkers(positions);
    else if (mapKindRef.current === 'tencent-2d') render2DMarkers(positions);
    else if (mapKindRef.current === 'leaflet') renderLeafletMarkers(positions);
    // 重置到默认中心
    try {
      if (mapKindRef.current === 'tencent-gl' && window.TMap) {
        const pos = new window.TMap.LatLng(31.230, 121.476);
        mapRef.current.setCenter(pos);
        mapRef.current.setZoom(12);
      } else if (mapKindRef.current === 'tencent-2d' && window.qq && window.qq.maps) {
        const pos = new window.qq.maps.LatLng(31.230, 121.476);
        mapRef.current.setCenter(pos);
        mapRef.current.setZoom(12);
      } else if (mapKindRef.current === 'leaflet' && window.L) {
        mapRef.current.setView([31.230, 121.476], 12);
      }
    } catch (e) {}
  };

  // Leaflet 渲染标记（用于搜索与重置）
  const renderLeafletMarkers = (list) => {
    if (!mapRef.current || !window.L) return;
    try {
      leafletLayerRef.current?.clearLayers?.();
    } catch (e) {}
    const L = window.L;
    leafletLayerRef.current = leafletLayerRef.current || L.layerGroup().addTo(mapRef.current);
    markersRef.current = [];
    markersIndexRef.current = {};
    const normalizedList = list.map(normalizeItem);
    const safeList = normalizedList.filter((p) => isValidLatLng(p.lat, p.lng));
    safeList.forEach((p) => {
      const content = `<div style="font-size:12px"><b>${p.equipmentName}</b><br/>设备号：${p.equipmentNo}<br/>位置：${p.locale}<br/>坐标：${p.lat}, ${p.lng}</div>`;
      const marker = L.marker([p.lat, p.lng]).addTo(leafletLayerRef.current).bindPopup(content);
      markersRef.current.push(marker);
      markersIndexRef.current[p.equipmentNo] = marker;
    });
    if (safeList.length > 0) {
      const first = safeList[0];
      mapRef.current.setView([first.lat, first.lng], Math.max(mapRef.current.getZoom?.() || 10, 10));
    }
  };

  // 右侧列表定位到地图坐标
  const locateOnMap = (item) => {
    if (!mapRef.current) {
      message.warning('地图尚未加载');
      return;
    }
    const viewZoom = typeof mapRef.current.getZoom === 'function' ? Math.max(mapRef.current.getZoom(), 13) : 13;
    const content = `<div style="font-size:12px"><b>${item.equipmentName}</b><br/>设备号：${item.equipmentNo}<br/>位置：${item.locale}<br/>坐标：${item.lat}, ${item.lng}</div>`;
    try {
      const latNum = toNumber(item?.lat);
      const lngNum = toNumber(item?.lng);
      const latOk = Number.isFinite(latNum);
      const lngOk = Number.isFinite(lngNum);
      if (!latOk || !lngOk) {
        message.warning('该设备坐标无效，无法定位');
        return;
      }
      if (mapKindRef.current === 'tencent-gl' && window.TMap) {
        const pos = new window.TMap.LatLng(latNum, lngNum);
        mapRef.current.setCenter(pos);
        mapRef.current.setZoom(viewZoom);
        try { mapRef.current.panTo?.(pos); } catch (e) {}
        infoWindowRef.current.setPosition(pos);
        infoWindowRef.current.setContent(content);
        infoWindowRef.current.open();
      } else if (mapKindRef.current === 'tencent-2d' && window.qq && window.qq.maps) {
        const pos = new window.qq.maps.LatLng(latNum, lngNum);
        mapRef.current.setCenter(pos);
        mapRef.current.setZoom(viewZoom);
        try { mapRef.current.panTo?.(pos); } catch (e) {}
        infoWindowRef.current.setContent(content);
        infoWindowRef.current.setPosition(pos);
        infoWindowRef.current.open();
      } else if (mapKindRef.current === 'leaflet' && window.L) {
        mapRef.current.setView([latNum, lngNum], viewZoom);
        const mk = markersIndexRef.current[item.equipmentNo];
        if (mk && typeof mk.openPopup === 'function') {
          mk.openPopup();
        } else {
          window.L.popup()
            .setLatLng([latNum, lngNum])
            .setContent(content)
            .openOn(mapRef.current);
        }
      }
    } catch (e) {}
  };

  const openDrawer = (item) => {
    setDrawerItem(item);
  };
  const closeDrawer = () => setDrawerItem(null);

  const onlineTag = (mqState) => (
    mqState === 1 ? <Tag color="success">在线</Tag> : mqState === 0 ? <Tag color="error">离线</Tag> : <Tag>-</Tag>
  );

  const handleRemoteControl = (item) => {
    message.info(`远程控制（模拟）：${item.equipmentName}`);
  };

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 12, height: 'calc(100vh - 60px - 32px)', overflow: 'hidden' }}>
      {/* 左侧地图 */}
      <Card variant="borderless" style={{ height: '100%' }} styles={{ body: { height: '100%', minHeight: 0, padding: 0 } }}>
        <Spin spinning={loading} tip="地图加载中...">
          <div id="mapBox" style={{ width: '100%', height: '100%', minHeight: 360, textAlign: 'center', position: 'relative' }}>
            {/* 当前地图引擎模式标识 */}
            {!loading && !mapError && mapMode && (
              <div style={{ position: 'absolute', left: 8, top: 8, zIndex: 2 }}>
                <Tag color="blue">地图引擎：{mapMode}</Tag>
              </div>
            )}
            {!loading && mapError && (
              <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', color: '#999' }}>
                <div style={{ fontSize: 16, marginBottom: 8 }}>设备地图</div>
                <div>{mapError}</div>
                <div style={{ marginTop: 4, fontSize: 12 }}>KEY 读取：{keyInfo}</div>
                <div style={{ marginTop: 8, fontSize: 12 }}>若需使用腾讯地图，请在 .env 中配置 VITE_TENCENT_MAP_KEY 后刷新页面。</div>
              </div>
            )}
          </div>
        </Spin>
      </Card>

      {/* 右侧设备栏（固定高度 + 内部滚动） */}
      <Card variant="borderless" style={{ height: '81%' }} styles={{ body: { height: '100%', minHeight: 0, overflow: 'hidden', padding: 0, display: 'flex', flexDirection: 'column' } }}>
        <div style={{ height: 50, display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 600 }}>设备筛选</div>
        <div style={{ padding: '0 12px 12px' }}>
          <Form form={form} layout="vertical" initialValues={search}>
            <Form.Item name="equipmentNo" label="设备编号">
              <Input allowClear placeholder="请输入设备编号" />
            </Form.Item>
            <Form.Item name="equipmentName" label="设备名称">
              <Input allowClear placeholder="请输入设备名称" />
            </Form.Item>
            <Space style={{ width: '100%', justifyContent: 'space-between' }}>
              <Button type="primary" onClick={handleSearch} style={{ width: '100px' }}>查询</Button>
              <Button onClick={handleReset} style={{ width: '100px' }}>重置</Button>
            </Space>
          </Form>
        </div>
        <div style={{ flex: 1, minHeight: 0, overflowY: 'scroll', overscrollBehavior: 'contain', padding: '8px 12px' }}>
          <Spin spinning={rightLoading} tip="加载设备列表...">
            {paginatedPositions.length > 0 ? (
              paginatedPositions.map((item, index) => (
                <div key={index} style={{ padding: '8px 0', borderBottom: '1px dashed #dcdfe6' }}>
                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                    <div>
                      <Button size="small" onClick={() => openDrawer(item)} style={{ marginRight: 8 }}>详情</Button>
                      <Button size="small" onClick={() => locateOnMap(item)} style={{ marginRight: 8 }}>定位</Button>
                    </div>
                    <Button size="small" onClick={() => handleRemoteControl(item)} style={{ background: '#ffbe6a', border: 0 }}>远程控制</Button>
                  </div>
                  <div style={{ marginTop: 8 }}>
                    <div><b>设备名称：</b>{item.equipmentName}</div>
                    <div><b>设备编号：</b>{item.equipmentNo}</div>
                    <div><b>用户昵称：</b>{item.nickName}</div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      <b>在线状态：</b>{onlineTag(item.mqState)}
                    </div>
                    <div style={{ display: '-webkit-box', overflow: 'hidden', WebkitBoxOrient: 'vertical', WebkitLineClamp: 2 }}>
                      <b>地理位置：</b>{item.locale}
                    </div>
                    <div><b>总购买数：</b>{item.totalNum}</div>
                    <div><b>总销售额：</b>￥{Number(item.totalSales).toLocaleString('zh-CN')}</div>
                    <div><b>在线时长：</b>{item.mqLen}</div>
                  </div>
                </div>
              ))
            ) : (
              <div style={{ textAlign: 'center', color: '#999', marginTop: 16 }}>无匹配设备</div>
            )}
          </Spin>
        </div>
        <div style={{ borderTop: '1px solid #f0f0f0', padding: '8px 12px', height: 52, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Pagination current={page} total={showPositions.length} pageSize={PAGE_SIZE} onChange={(p) => setPage(p)} showSizeChanger={false} />
        </div>
      </Card>

      {/* 详情抽屉 */}
      <Drawer open={!!drawerItem} onClose={closeDrawer} width={380} title="设备详情">
        {drawerItem && (
          <div style={{ display: 'grid', gap: 8 }}>
            <div><b>设备名称：</b>{drawerItem.equipmentName}</div>
            <div><b>设备编号：</b>{drawerItem.equipmentNo}</div>
            <div><b>用户昵称：</b>{drawerItem.nickName}</div>
            <div><b>地理位置：</b>{drawerItem.locale}</div>
            <div><b>在线状态：</b>{drawerItem.mqState === 1 ? '在线' : drawerItem.mqState === 0 ? '离线' : '-'}</div>
            <Space>
              <Button type="primary" onClick={() => message.success('模拟：发送远程控制指令')}>远程控制</Button>
              <Button danger onClick={() => message.success('模拟：发送重启板子指令')}>重启板子</Button>
            </Space>
          </div>
        )}
      </Drawer>
    </div>
  );
}